Bug in PostNuke 0.62, 0.63 and 0.64 (and possibly PHPnuke)
Date: Samstag, 13. Oktober 2001 17:55
----- IMPACT -----
If an attacker knows the username and userid of a user on a
PostNuked system, it is possible to log in as the user without
specifying a password.
Userid/username is usually available from the Members list.
A fix is available at the end of this document.
----- AFFECTED VERSIONS -----
PostNuke 0.62, 0.63, 0.64
PHPnuke is not tested. Version 5.2 (and earlier) contains the
same code as PostNuke and could be vulnerable.
----- BACKGROUND -----
The vulnerable code is located in article.php and mainfile2.php
(mainfile.php):
o article.php:
if ($save) {
cookiedecode($user);
mysql_query("update $pntable[users] set umode='$mode',
uorder='$order', thold='$thold' where uid='$cookie[0]'");
getusrinfo($user);
$info =
base64_encode("$userinfo[uid]:$userinfo[uname]:$userinfo[pass]:$u
serinfo[storynum]:$userinfo[umode]:$userinfo[uorder]:$userinfo[th
old]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
o mainfile2.php (mainfile.php in PHPnuke and older versions of
PostNuke):
function getusrinfo($user) {
global $userinfo, $pntable;
$user2 = base64_decode($user);
$user3 = explode(":", $user2);
$result = mysql_query("select uid, name, uname, email,
femail, url, user_avatar, user_icq, user_occ, user_from,
user_intrest, user_sig, user_viewemail, user_theme, user_aim,
user_yim, user_msnm, pass, storynum, umode, uorder, thold,
noscore, bio, ublockon, ublock, theme, commentmax,
timezone_offset from $pntable[users] where uname='$user3[1]' and
pass='$user3[2]'");
if(mysql_num_rows($result)==1) {
$userinfo = mysql_fetch_array($result);
} else {
echo ""._MPROBLEM."
";
}
return $userinfo;
}
The bug is a result of the following issues:
o It is possible to invoke the if-clause in article.php by just
specifying save=1 in the URL.
o article.php blindly accepts the $user variable specified in the
URL.
o There is no code in article.php that checks if cookiedecode()
actually worked and the password specified in $user is not
checked against the MySQL-database.
o article.php accepts the $cookieusrtime variable as specified in
the URL.
o It is possible to modify the mysql_query-string in getusrinfo()
by escaping the "'" in $user[1] or $user[2]. Like this (without
the double-quotes):
"' or uname='USERNAME".
getusrinfo() will then return anything with uname=USERNAME, even
if the password doesn't match the one in $user. The full
query-string sent to mysql will end up looking like this:
select uid, name, uname, email, femail, url, user_avatar,
user_icq,
user_occ, user_from, user_intrest, user_sig, user_viewemail,
user_theme,
user_aim, user_yim, user_msnm, pass, storynum, umode, uorder,
thold, noscore,
bio, ublockon, ublock, theme, commentmax, timezone_offset from
$prefix"._users."
where uname='USERNAME' and pass='' or uname='USERNAME'
To produce the query above the $user variable should contain a
base64-encoded version of:
USERID:USERNAME:' or uname 'USERNAME' (base64_encoded)
o When the userinfo is received from getusrinfo() by article.php,
it blindly sets a "user="-cookie containing the encrypted
password.
----- EXPLOIT -----
If an attacker requests a URL consisting of...
article.php?save=1&
sid=20& [any sid will do..]
cookieusrtime=160000& [to get a decent expire-date on the
cookie]
user=USERID:USERNAME:' or uname='USERNAME [base64_encoded]
... and goes back to the mainpage, (s)he will be logged in as
USERNAME.
----- FIX -----
Thanks to Sascha Endlicher and John Cox (www.postnuke.com) for
comming up with the fix below.
In article.php, change the offending code to:
if (($save) && (is_user($user))) {
cookiedecode($user);
mysql_query("update $pntable[users] set umode='$mode',
uorder='$order', thold='$thold' where uid='$cookie[0]'");
getusrinfo($user);
$info =
base64_encode("$userinfo[uid]:$userinfo[uname]:$userinfo[pass]:$u
serinfo[storynum]:$userinfo[umode]:$userinfo[uorder]:$userinfo[th
old]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
This may work in PHPnuke as well.
A new version of article.php for PostNuke is available from
https://sourceforge.net/project/showfiles.php?group_id=27927
under Fixes.
Magnus Skjegstad
magnus at skjegstad.com